import {
  IsString,
  IsOptional,
  IsEnum,
  IsBoolean,
  IsNumber,
  IsObject,
  IsArray,
  MinLength,
  MaxLength,
  IsEmail,
  IsUrl,
  IsInt,
  Min,
  Max,
  ValidateNested,
  IsJSON
} from 'class-validator'
import { Transform, Type } from 'class-transformer'
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
import { PaginationDto } from './base.dto'
import { IsColor, IsUrlWithChinese } from '../validators/custom.validators'

/**
 * 设置类型枚举
 */
export enum SettingType {
  STRING = 'string',
  NUMBER = 'number',
  BOOLEAN = 'boolean',
  JSON = 'json',
  ARRAY = 'array',
  EMAIL = 'email',
  URL = 'url',
  COLOR = 'color',
  FILE = 'file',
  IMAGE = 'image'
}

/**
 * 设置分组枚举
 */
export enum SettingGroup {
  GENERAL = 'general',
  SITE = 'site',
  EMAIL = 'email',
  UPLOAD = 'upload',
  SECURITY = 'security',
  SEO = 'seo',
  SOCIAL = 'social',
  THEME = 'theme',
  CACHE = 'cache',
  API = 'api',
  NOTIFICATION = 'notification',
  BACKUP = 'backup'
}

/**
 * 创建设置DTO
 */
export class CreateSettingDto {
  @ApiProperty({ description: '设置键名', example: 'site_title' })
  @IsString({ message: '设置键名必须是字符串' })
  @MinLength(1, { message: '设置键名不能为空' })
  @MaxLength(100, { message: '设置键名不能超过100个字符' })
  @Transform(({ value }) =>
    value
      ?.toLowerCase()
      .trim()
      .replace(/[^a-z0-9_]/g, '_')
  )
  key: string

  @ApiProperty({ description: '设置值', example: '我的网站' })
  @IsString({ message: '设置值必须是字符串' })
  value: string

  @ApiProperty({ description: '设置名称', example: '网站标题' })
  @IsString({ message: '设置名称必须是字符串' })
  @MinLength(1, { message: '设置名称不能为空' })
  @MaxLength(100, { message: '设置名称不能超过100个字符' })
  @Transform(({ value }) => value?.trim())
  name: string

  @ApiPropertyOptional({ description: '设置描述', example: '网站的主标题，显示在浏览器标题栏' })
  @IsOptional()
  @IsString({ message: '设置描述必须是字符串' })
  @MaxLength(500, { message: '设置描述不能超过500个字符' })
  @Transform(({ value }) => value?.trim())
  description?: string

  @ApiProperty({ description: '设置类型', enum: SettingType, example: SettingType.STRING })
  @IsEnum(SettingType, { message: '设置类型不正确' })
  type: SettingType

  @ApiProperty({ description: '设置分组', enum: SettingGroup, example: SettingGroup.SITE })
  @IsEnum(SettingGroup, { message: '设置分组不正确' })
  group: SettingGroup

  @ApiPropertyOptional({ description: '默认值', example: '默认网站标题' })
  @IsOptional()
  @IsString({ message: '默认值必须是字符串' })
  defaultValue?: string

  @ApiPropertyOptional({ description: '是否必填', example: true })
  @IsOptional()
  @IsBoolean({ message: '是否必填必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  required?: boolean = false

  @ApiPropertyOptional({ description: '是否只读', example: false })
  @IsOptional()
  @IsBoolean({ message: '是否只读必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  readonly?: boolean = false

  @ApiPropertyOptional({ description: '是否隐藏', example: false })
  @IsOptional()
  @IsBoolean({ message: '是否隐藏必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  hidden?: boolean = false

  @ApiPropertyOptional({ description: '排序权重', example: 100 })
  @IsOptional()
  @IsInt({ message: '排序权重必须是整数' })
  @Min(0, { message: '排序权重不能小于0' })
  @Max(9999, { message: '排序权重不能大于9999' })
  @Transform(({ value }) => parseInt(value, 10))
  sortOrder?: number = 100

  @ApiPropertyOptional({ description: '验证规则（JSON格式）', example: '{"min": 1, "max": 100}' })
  @IsOptional()
  @IsJSON({ message: '验证规则必须是有效的JSON格式' })
  validationRules?: string

  @ApiPropertyOptional({
    description: '选项列表（JSON格式，用于下拉框等）',
    example: '[{"label": "选项1", "value": "option1"}]'
  })
  @IsOptional()
  @IsJSON({ message: '选项列表必须是有效的JSON格式' })
  options?: string

  @ApiPropertyOptional({ description: '帮助文本', example: '请输入网站的主标题' })
  @IsOptional()
  @IsString({ message: '帮助文本必须是字符串' })
  @MaxLength(1000, { message: '帮助文本不能超过1000个字符' })
  @Transform(({ value }) => value?.trim())
  helpText?: string

  @ApiPropertyOptional({ description: '占位符文本', example: '请输入网站标题' })
  @IsOptional()
  @IsString({ message: '占位符文本必须是字符串' })
  @MaxLength(200, { message: '占位符文本不能超过200个字符' })
  @Transform(({ value }) => value?.trim())
  placeholder?: string
}

/**
 * 更新设置DTO
 */
export class UpdateSettingDto {
  @ApiPropertyOptional({ description: '设置值', example: '我的网站' })
  @IsOptional()
  @IsString({ message: '设置值必须是字符串' })
  value?: string

  @ApiPropertyOptional({ description: '设置名称', example: '网站标题' })
  @IsOptional()
  @IsString({ message: '设置名称必须是字符串' })
  @MinLength(1, { message: '设置名称不能为空' })
  @MaxLength(100, { message: '设置名称不能超过100个字符' })
  @Transform(({ value }) => value?.trim())
  name?: string

  @ApiPropertyOptional({ description: '设置描述', example: '网站的主标题，显示在浏览器标题栏' })
  @IsOptional()
  @IsString({ message: '设置描述必须是字符串' })
  @MaxLength(500, { message: '设置描述不能超过500个字符' })
  @Transform(({ value }) => value?.trim())
  description?: string

  @ApiPropertyOptional({ description: '设置类型', enum: SettingType, example: SettingType.STRING })
  @IsOptional()
  @IsEnum(SettingType, { message: '设置类型不正确' })
  type?: SettingType

  @ApiPropertyOptional({ description: '设置分组', enum: SettingGroup, example: SettingGroup.SITE })
  @IsOptional()
  @IsEnum(SettingGroup, { message: '设置分组不正确' })
  group?: SettingGroup

  @ApiPropertyOptional({ description: '默认值', example: '默认网站标题' })
  @IsOptional()
  @IsString({ message: '默认值必须是字符串' })
  defaultValue?: string

  @ApiPropertyOptional({ description: '是否必填', example: true })
  @IsOptional()
  @IsBoolean({ message: '是否必填必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  required?: boolean

  @ApiPropertyOptional({ description: '是否只读', example: false })
  @IsOptional()
  @IsBoolean({ message: '是否只读必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  readonly?: boolean

  @ApiPropertyOptional({ description: '是否隐藏', example: false })
  @IsOptional()
  @IsBoolean({ message: '是否隐藏必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  hidden?: boolean

  @ApiPropertyOptional({ description: '排序权重', example: 100 })
  @IsOptional()
  @IsInt({ message: '排序权重必须是整数' })
  @Min(0, { message: '排序权重不能小于0' })
  @Max(9999, { message: '排序权重不能大于9999' })
  @Transform(({ value }) => parseInt(value, 10))
  sortOrder?: number

  @ApiPropertyOptional({ description: '验证规则（JSON格式）', example: '{"min": 1, "max": 100}' })
  @IsOptional()
  @IsJSON({ message: '验证规则必须是有效的JSON格式' })
  validationRules?: string

  @ApiPropertyOptional({
    description: '选项列表（JSON格式，用于下拉框等）',
    example: '[{"label": "选项1", "value": "option1"}]'
  })
  @IsOptional()
  @IsJSON({ message: '选项列表必须是有效的JSON格式' })
  options?: string

  @ApiPropertyOptional({ description: '帮助文本', example: '请输入网站的主标题' })
  @IsOptional()
  @IsString({ message: '帮助文本必须是字符串' })
  @MaxLength(1000, { message: '帮助文本不能超过1000个字符' })
  @Transform(({ value }) => value?.trim())
  helpText?: string

  @ApiPropertyOptional({ description: '占位符文本', example: '请输入网站标题' })
  @IsOptional()
  @IsString({ message: '占位符文本必须是字符串' })
  @MaxLength(200, { message: '占位符文本不能超过200个字符' })
  @Transform(({ value }) => value?.trim())
  placeholder?: string
}

/**
 * 设置查询DTO
 */
export class QuerySettingDto extends PaginationDto {
  @ApiPropertyOptional({ description: '搜索关键词（设置键名、名称、描述）', example: 'title' })
  @IsOptional()
  @IsString({ message: '搜索关键词必须是字符串' })
  @MaxLength(100, { message: '搜索关键词不能超过100个字符' })
  @Transform(({ value }) => value?.trim())
  search?: string = ''

  @ApiPropertyOptional({ description: '设置分组', enum: SettingGroup, example: SettingGroup.SITE })
  @IsOptional()
  @IsEnum(SettingGroup, { message: '设置分组不正确' })
  group?: SettingGroup

  @ApiPropertyOptional({ description: '设置类型', enum: SettingType, example: SettingType.STRING })
  @IsOptional()
  @IsEnum(SettingType, { message: '设置类型不正确' })
  type?: SettingType

  @ApiPropertyOptional({ description: '是否必填', example: true })
  @IsOptional()
  @IsBoolean({ message: '是否必填必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  required?: boolean

  @ApiPropertyOptional({ description: '是否只读', example: false })
  @IsOptional()
  @IsBoolean({ message: '是否只读必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  readonly?: boolean

  @ApiPropertyOptional({ description: '是否隐藏', example: false })
  @IsOptional()
  @IsBoolean({ message: '是否隐藏必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  hidden?: boolean
}

/**
 * 设置响应DTO
 */
export class SettingResponseDto {
  @ApiProperty({ description: '设置ID', example: 'uuid-123' })
  id: string

  @ApiProperty({ description: '设置键名', example: 'site_title' })
  key: string

  @ApiProperty({ description: '设置值', example: '我的网站' })
  value: string

  @ApiProperty({ description: '设置名称', example: '网站标题' })
  name: string

  @ApiPropertyOptional({ description: '设置描述', example: '网站的主标题，显示在浏览器标题栏' })
  description?: string

  @ApiProperty({ description: '设置类型', enum: SettingType, example: SettingType.STRING })
  type: SettingType

  @ApiProperty({ description: '设置分组', enum: SettingGroup, example: SettingGroup.SITE })
  group: SettingGroup

  @ApiPropertyOptional({ description: '默认值', example: '默认网站标题' })
  defaultValue?: string

  @ApiProperty({ description: '是否必填', example: true })
  required: boolean

  @ApiProperty({ description: '是否只读', example: false })
  readonly: boolean

  @ApiProperty({ description: '是否隐藏', example: false })
  hidden: boolean

  @ApiProperty({ description: '排序权重', example: 100 })
  sortOrder: number

  @ApiPropertyOptional({ description: '验证规则', example: { min: 1, max: 100 } })
  validationRules?: any

  @ApiPropertyOptional({ description: '选项列表', example: [{ label: '选项1', value: 'option1' }] })
  options?: any[]

  @ApiPropertyOptional({ description: '帮助文本', example: '请输入网站的主标题' })
  helpText?: string

  @ApiPropertyOptional({ description: '占位符文本', example: '请输入网站标题' })
  placeholder?: string

  @ApiPropertyOptional({ description: '创建者信息' })
  creator?: {
    id: string
    username: string
    realName?: string
  }

  @ApiPropertyOptional({ description: '最后更新者信息' })
  updater?: {
    id: string
    username: string
    realName?: string
  }

  @ApiProperty({ description: '创建时间', example: '2024-01-01T00:00:00.000Z' })
  createdAt: Date

  @ApiProperty({ description: '更新时间', example: '2024-01-01T00:00:00.000Z' })
  updatedAt: Date
}

/**
 * 批量更新设置DTO
 */
export class BulkUpdateSettingDto {
  @ApiProperty({ description: '设置列表', type: [Object] })
  @IsArray({ message: '设置列表必须是数组' })
  @ValidateNested({ each: true })
  @Type(() => SettingUpdateItem)
  settings: SettingUpdateItem[]
}

/**
 * 设置更新项DTO
 */
export class SettingUpdateItem {
  @ApiProperty({ description: '设置键名', example: 'site_title' })
  @IsString({ message: '设置键名必须是字符串' })
  key: string

  @ApiProperty({ description: '设置值', example: '我的网站' })
  @IsString({ message: '设置值必须是字符串' })
  value: string
}

/**
 * 设置分组响应DTO
 */
export class SettingGroupResponseDto {
  @ApiProperty({ description: '分组名称', enum: SettingGroup, example: SettingGroup.SITE })
  group: SettingGroup

  @ApiProperty({ description: '分组显示名称', example: '网站设置' })
  groupName: string

  @ApiProperty({ description: '分组描述', example: '网站基本信息配置' })
  groupDescription: string

  @ApiProperty({ description: '设置列表', type: [SettingResponseDto] })
  settings: SettingResponseDto[]

  @ApiProperty({ description: '设置数量', example: 10 })
  settingCount: number
}

/**
 * 设置统计DTO
 */
export class SettingStatsDto {
  @ApiProperty({ description: '总设置数', example: 50 })
  total: number

  @ApiProperty({ description: '各分组设置数统计' })
  groupStats: Record<SettingGroup, number>

  @ApiProperty({ description: '各类型设置数统计' })
  typeStats: Record<SettingType, number>

  @ApiProperty({ description: '必填设置数', example: 15 })
  requiredCount: number

  @ApiProperty({ description: '只读设置数', example: 5 })
  readonlyCount: number

  @ApiProperty({ description: '隐藏设置数', example: 3 })
  hiddenCount: number

  @ApiProperty({ description: '最近更新的设置' })
  recentUpdated: Array<{
    key: string
    name: string
    value: string
    updatedAt: Date
    updaterName: string
  }>
}

/**
 * 设置导入DTO
 */
export class ImportSettingDto {
  @ApiProperty({ description: '设置数据列表', type: [CreateSettingDto] })
  @IsArray({ message: '设置数据列表必须是数组' })
  @ValidateNested({ each: true })
  @Type(() => CreateSettingDto)
  settings: CreateSettingDto[]

  @ApiPropertyOptional({ description: '是否覆盖已存在的设置', example: false })
  @IsOptional()
  @IsBoolean({ message: '是否覆盖已存在的设置必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  overwrite?: boolean = false

  @ApiPropertyOptional({ description: '导入模式', enum: ['create', 'update', 'upsert'] })
  @IsOptional()
  @IsEnum(['create', 'update', 'upsert'], { message: '导入模式不正确' })
  mode?: 'create' | 'update' | 'upsert' = 'create'
}

/**
 * 设置导出DTO
 */
export class ExportSettingDto {
  @ApiPropertyOptional({ description: '导出分组', enum: SettingGroup, isArray: true })
  @IsOptional()
  @IsArray({ message: '导出分组必须是数组' })
  @IsEnum(SettingGroup, { each: true, message: '导出分组不正确' })
  groups?: SettingGroup[]

  @ApiPropertyOptional({ description: '导出类型', enum: SettingType, isArray: true })
  @IsOptional()
  @IsArray({ message: '导出类型必须是数组' })
  @IsEnum(SettingType, { each: true, message: '导出类型不正确' })
  types?: SettingType[]

  @ApiPropertyOptional({ description: '是否包含隐藏设置', example: false })
  @IsOptional()
  @IsBoolean({ message: '是否包含隐藏设置必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  includeHidden?: boolean = false

  @ApiPropertyOptional({ description: '导出格式', enum: ['json', 'yaml', 'env'] })
  @IsOptional()
  @IsEnum(['json', 'yaml', 'env'], { message: '导出格式不正确' })
  format?: 'json' | 'yaml' | 'env' = 'json'
}

/**
 * 设置重置DTO
 */
export class ResetSettingDto {
  @ApiPropertyOptional({ description: '重置分组', enum: SettingGroup, isArray: true })
  @IsOptional()
  @IsArray({ message: '重置分组必须是数组' })
  @IsEnum(SettingGroup, { each: true, message: '重置分组不正确' })
  groups?: SettingGroup[]

  @ApiPropertyOptional({
    description: '重置设置键名列表',
    example: ['site_title', 'site_description']
  })
  @IsOptional()
  @IsArray({ message: '重置设置键名列表必须是数组' })
  @IsString({ each: true, message: '设置键名必须是字符串' })
  keys?: string[]

  @ApiPropertyOptional({ description: '是否确认重置', example: true })
  @IsBoolean({ message: '是否确认重置必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  confirm: boolean
}
